<?php
/**
 *备货需求(缺货，自动备货，特采需求)公共模型
 */
class Application_Model_Story extends Model_Base {
	//需求拦截类型-因需求仓与销售仓互斥而被拦截
	const WAREHOUSE_CONFLICT_INTERCEPT_TYPE = 1;

	//需求类型；依次为缺货需求，特采需求，自动备货需求
	const A_STORY_TYPE = 'a';
	const B_STORY_TYPE = 'b';
	const C_STORY_TYPE = 'c';

	//需求审核状态
	const INIT_EXAMINE_STATUS = 0;
	const WAIT_PRIMARY_TEAM_LEADER_EXAMINE = 1; //待小组长审核
	const WAIT_ADVANCED_TEAM_LEADER_EXAMINE = 2; //待大组长审核
	const WAIT_TEAM_MANAGER_EXAMINE = 3; //待主管审核
	const WAIT_MANAGER_EXAMINE = 4; //待经理审核
	const EXAMINE_PASS = 5; //审核通过
	const PRIMARY_TEAM_LEADER_REJECT = 6; //小组长驳回
	const ADVANCED_TEAM_LEADER_REJECT = 7; //大组长驳回
	const TEAM_MANAGER_REJECT = 8; //主管驳回
	const MANAGER_REJECT = 9; //经理驳回

	//所有的需求审核状态
	const ALL_EXAMINE_STATUS = [
		self::INIT_EXAMINE_STATUS => '初始',
		self::WAIT_PRIMARY_TEAM_LEADER_EXAMINE => '待小组长审核',
		self::WAIT_ADVANCED_TEAM_LEADER_EXAMINE => '待大组长审核',
		self::WAIT_TEAM_MANAGER_EXAMINE => '待主管审核',
		self::WAIT_MANAGER_EXAMINE => '待经理审核',
		self::EXAMINE_PASS => '审核通过',
		self::PRIMARY_TEAM_LEADER_REJECT => '小组长驳回',
		self::ADVANCED_TEAM_LEADER_REJECT => '大组长驳回',
		self::TEAM_MANAGER_REJECT => '主管驳回',
		self::MANAGER_REJECT => '经理驳回',
	];

	//需求审核操作类型
	const PRIMARY_TEAM_LEADER_AGREE_OPERATION = 1; //小组长审核通过
	const ADVANCED_TEAM_LEADER_AGREE_OPERATION = 2; //大组长审核通过
	const TEAM_MANAGER_AGREE_OPERATION = 3; //主管审核通过
	const MANAGER_AGREE_OPERATION = 4; //经理审核通过
	const PRIMARY_TEAM_LEADER_REJECT_OPERATION = 5; //小组长驳回
	const ADVANCED_TEAM_LEADER_REJECT_OPERATION = 6; //大组长驳回
	const TEAM_MANAGER_REJECT_OPERATION = 7; //主管驳回
	const MANAGER_REJECT_OPERATION = 8; //经理驳回

	public function __construct() {
		$this->db = $this->db();
		$this->writeDb = $this->db("write_db");
	}

	/**
	 * 是否是合法的审核状态
	 * @param  [type]  $examineStatus [description]
	 * @return boolean                [description]
	 */
	static function isValidExamineStatus($examineStatus) {
		return in_array($examineStatus, array_keys(self::ALL_EXAMINE_STATUS));
	}

	/**
	 * 根据id获取一条需求记录
	 * @param  int    $storyId [description]
	 * @return [TYPE]          [description]
	 */
	public function getOneById(int $storyId) {
		return $this->writeDb->fetchRow("select * from b_story where id=" . $storyId);
	}

	/**
	 * 更新需求审核状态
	 * @param  int     $storyId           被更新状态的需求id
	 * @param  int     $afterChangeStatus 需求更新后的状态
	 * @param  boolean $isUseTransaction  是否使用事物，默认是使用
	 * @return bool
	 */
	public function statusUpdate(int $storyId, int $afterChangeStatus, $isUseTransaction = true) {
		if (!self::isValidExamineStatus($afterChangeStatus)) {
			return $this->_error('非法的需求审核状态：' . $afterChangeStatus);
		}
		$storyInfo = $this->getOneById($storyId);
		if (!$storyInfo) {
			return $this->_error('未找到需求id为:' . $storyId . '的需求！');
		}
		$goodsSn = $storyInfo['goods_sn'];
		$warehouse = $storyInfo['warehouse_code'];
		//检查商品是否已经有更新后状态需求，如果有，合并需求为同一条需求
		$otherSameStatusStory = $this->getOneByExamineStatus($goodsSn, $warehouse, $afterChangeStatus, $storyInfo['platform_warehouse']);

		$isUseTransaction && $this->writeDb->beginTransaction();
		try {
			if ($otherSameStatusStory) {
				$this->delete($otherSameStatusStory['id']);
				$updateData = [
					'a_story_quantity' => $storyInfo['a_story_quantity'] + $otherSameStatusStory['a_story_quantity'],
					'b_story_quantity' => $storyInfo['b_story_quantity'] + $otherSameStatusStory['b_story_quantity'],
					'c_story_quantity' => $storyInfo['c_story_quantity'] + $otherSameStatusStory['c_story_quantity'],
				];
			}
			$updateWhere = $this->writeDb->quoteInto('id=?', $storyId);
			$updateData['examine_status'] = $afterChangeStatus;
			$this->writeDb->update('b_story', $updateData, $updateWhere);

			//如果需求是审核通过的状态了，就加到传输需求到pms队列
			if ($afterChangeStatus == self::EXAMINE_PASS) {
				$this->addToTransferQueue($storyId);
			}

			$isUseTransaction && $this->writeDb->commit();
			return true;
		} catch (Exception $e) {
			$isUseTransaction && $this->writeDb->rollBack();
			return $this->_error($e->getMessage());
		}

	}

	/**
	 *根据产品和产品备货仓库获取需求
	 * @param  [type] $backupGoodsSn     备货产品goods_sn
	 * @param  [type] $backupWarehouse   产品要备货的仓库
	 * @param  [type] $platformWarehouse 产品备货仓库所属平台仓
	 * @param  [type] $date(Y-m-d)       产品备货时间，默认为当天
	 * @return 成功时返回二维数组
	 */
	public function get($backupGoodsSn, $backupWarehouse, $platformWarehouse = "", $date = null) {
		$where = $this->db->quoteInto("goods_sn=?", $backupGoodsSn);
		if ($backupWarehouse) {
			$where .= " AND " . $this->db->quoteInto("warehouse_code=?", $backupWarehouse);
		}
		if (is_null($date)) {
			$date = date("Y-m-d");
		}
		$where .= " AND " . $this->db->quoteInto("platform_warehouse=?", $platformWarehouse);
		$where .= " AND " . $this->db->quoteInto("create_date=?", $date);
		return $this->db->fetchAll("select * from b_story where $where");
	}

	/**
	 * 根据需求审核状态获取需求
	 * @return [type] [description]
	 */
	public function getOneByExamineStatus($goodsSn, $warehouse, int $examineStatus, $platformWarehouse = "", $createDate = null) {
		$where = $this->writeDb->quoteInto("goods_sn=?", $goodsSn);
		$where .= " AND " . $this->writeDb->quoteInto("warehouse_code=?", trim($warehouse));
		if (is_null($createDate)) {
			$createDate = date("Y-m-d");
		}
		$where .= " AND " . $this->writeDb->quoteInto("platform_warehouse=?", trim($platformWarehouse));
		$where .= " AND " . $this->writeDb->quoteInto("create_date=?", $createDate);
		$where .= " AND " . $this->writeDb->quoteInto('examine_status=?', $examineStatus);
		$where .= " AND " . $this->writeDb->quoteInto('delete_flag=?', 0);

		return $this->writeDb->fetchRow("select * from b_story where $where");
	}

	/**
	 * 生成产品备货需求(如果产品当日已有同类，同待审核的状态需求则需求数量会累加，不会重新生成一条[根据数据库唯一索引来判断])
	 * @param  [type] $goodsSn           备货产品
	 * @param  [type] $warehouse         备货仓库
	 * @param  [type] $storyType         需求类型(有:a,b,c)
	 * @param  int    $storyQuantity     备货数量
	 * @param  string $platformWarehouse 产品所属平台仓
	 * @param  string $createDate        需求生成时间，默认为当天
	 * @return bool
	 */
	public function create($goodsSn, $warehouse, $storyType, int $storyQuantity, $platformWarehouse = "", $createDate = "") {
		return $this->_create(trim($goodsSn), trim($warehouse), strtolower($storyType), $storyQuantity, trim($platformWarehouse), $createDate);
	}

	protected function _create($goodsSn, $warehouse, $storyType, int $storyQuantity, $platformWarehouse = "", $createDate = "", $examineStatus = 0) {
		$storyTypeQuantityFields = ['a' => 'a_story_quantity', 'b' => 'b_story_quantity', 'c' => 'c_story_quantity'];
		$quantityFields = $storyTypeQuantityFields[$storyType] ?? false;
		if (!$quantityFields) {
			return $this->_error('未知需求类型：' . $storyType);
		}
		$quantityFields = $this->writeDb->quoteIdentifier($quantityFields);
		if (!$createDate) {
			$createDate = date("Y-m-d");
		}

		if ($examineStatus !== 0) {
			if (!$this->isValidExamineStatus($examineStatus)) {
				return $this->_error('未知的需求审核类型！');
			}
		}

		$goodsSn = $this->writeDb->quote($goodsSn);
		$warehouse = $this->writeDb->quote($warehouse);
		$createDate = $this->writeDb->quote($createDate);
		$platformWarehouse = $this->writeDb->quote($platformWarehouse);
		try {
			$this->writeDb->query("INSERT INTO b_story (goods_sn,warehouse_code,platform_warehouse,create_date,$quantityFields,examine_status,delete_flag) VALUES($goodsSn,$warehouse,$platformWarehouse,$createDate,$storyQuantity,$examineStatus,0) ON DUPLICATE KEY UPDATE $quantityFields=$quantityFields+$storyQuantity");
			return true;
		} catch (Exception $e) {
			return $this->_error($e->getMessage());
		}
	}

	/**
	 * 删除需求
	 * @param  int|array $storyId 需求id，支持批量删除[1,2,3]
	 * @return [type]          [description]
	 */
	public function delete($storyId) {
		$storyId = is_array($storyId) ? $storyId : [$storyId];
		$where = $this->writeDb->quoteInto("id IN(?)", $storyId);
		return $this->writeDb->update('b_story', ['delete_flag' => 1], $where);
	}

	/**
	 * 更新需求数量
	 * @param  int    $storyId     被更新的需求id
	 * @param  [type] $storyType   更新数量的需求类型
	 * @param  int    $newQuantity 数量更新值
	 * @param  [type] $updateReason 需求数量修改原因
	 * @param  string $modifyUser  需求数量修改人
	 * @return [type]              [description]
	 */
	public function updateQuantity(int $storyId, $storyType, int $newQuantity, $updateReason, $modifyUser = 'system', $isUseTransaction = true) {
		$storyTypeQuantityFields = ['a' => 'a_story_quantity', 'b' => 'b_story_quantity', 'c' => 'c_story_quantity'];
		$quantityFields = $storyTypeQuantityFields[$storyType] ?? false;
		if (!$quantityFields) {
			return $this->_error('未知需求类型：' . $storyType);
		}
		$where = $this->writeDb->quoteInto("id=?", $storyId);
		$storyInfo = $this->writeDb->fetchRow('select * from b_story where ' . $where);
		if (empty($storyInfo)) {
			return $this->_error('id为:' . $storyId . '的需求不存在！');
		}
		if (!$this->_allowModifyQuantity($storyInfo)) {
			return $this->_error('id为:' . $storyId . '的需求当前状态不允许修改数量！');
		}

		$storyOldQuantity = $storyInfo[$quantityFields];
		if ($newQuantity == $storyOldQuantity) {
			return $this->_error('需求更改后的数量不能原数量一样！');
		}

		$isUseTransaction && $this->writeDb->beginTransaction();
		try {
			$updateData = [
				$quantityFields => $newQuantity,
			];
			//数量更新后，需求备货数是否是零？如果是,删除该需求
			if ($newQuantity === 0) {
				$storyALLQuantity = 0;
				foreach ($storyTypeQuantityFields as $_quantityFields) {
					if ($_quantityFields != $quantityFields) {
						$storyALLQuantity + $storyInfo[$_quantityFields];
					}
				}
				unset($_quantityFields);
				if ($storyALLQuantity === 0) {
					$updateData['delete_flag'] = 1;
				}
			}
			$this->writeDb->update('b_story', $updateData, $where);

			$quantityChange = $newQuantity - $storyOldQuantity;
			$updateReason .= ' 需求' . $storyType . '的数量' . ($quantityChange < 0 ? '扣减' : '增加') . ':' . abs($quantityChange);
			$this->addQuantityModifyLog($storyId, $storyType, $storyOldQuantity, $newQuantity, $updateReason, $modifyUser);

			$isUseTransaction && $this->writeDb->commit();
			return true;
		} catch (Exception $e) {
			$isUseTransaction && $this->writeDb->rollBack();
			return $this->_error($e->getMessage());
		}
	}

	/**
	 * 添加需求修改日志
	 * @param [type] $storyId     需求id
	 * @param [type] $storyType   需求类型 (a|b|c)
	 * @param [type] $oldQuantity 需求数量旧值
	 * @param [type] $newQuantity 需求数量新值
	 * @param [type] $remark      需求数量修改备注
	 * @param [type] $modifyUser  需求数量修改人
	 */
	public function addQuantityModifyLog($storyId, $storyType, $oldQuantity, $newQuantity, $remark, $modifyUser = 'system') {
		$quantityModifyLog['old_quantity'] = $oldQuantity;
		$quantityModifyLog['new_quantity'] = $newQuantity;

		$quantityModifyLog['remark'] = $remark;
		$quantityModifyLog['modify_user'] = $modifyUser;
		$quantityModifyLog['story_type'] = $storyType;
		$quantityModifyLog['story_id'] = $storyId;
		return $this->writeDb->insert('b_story_quantity_modify_log', $quantityModifyLog);
	}

	/**
	 * 当前需求是否允许修改数量
	 * @param  array  $oneStory [description]
	 * @return [type]           [description]
	 */
	protected function _allowModifyQuantity(array $oneStory) {
		$_allowModifyQuantityStatus = [
			self::INIT_EXAMINE_STATUS,
			self::WAIT_PRIMARY_TEAM_LEADER_EXAMINE,
			self::WAIT_ADVANCED_TEAM_LEADER_EXAMINE,
			self::WAIT_TEAM_MANAGER_EXAMINE,
			self::WAIT_MANAGER_EXAMINE,
		];
		if (in_array($oneStory['examine_status'], $_allowModifyQuantityStatus) && $oneStory['delete_flag'] != 1) {
			return true;
		}

		//被驳回的需求可以被修改
		$hasReject = $this->writeDb->fetchOne("select count(*) from b_reject_story where story_id=" . $oneStory['id'] . ' and reject_result="待处理"');
		if ($hasReject) {
			return true;
		}

		return false;
	}

	/**
	 * 是否是合法的需求类
	 * @param  [type]  $type 需求类型
	 * @return boolean       [description]
	 */
	public static function isValidType($type) {
		return in_array($type, [self::A_STORY_TYPE, self::B_STORY_TYPE, self::C_STORY_TYPE]);
	}

	public static function getExamineStatusName(int $examineStatus) {
		return self::ALL_EXAMINE_STATUS[$examineStatus] ?? "未知需求审核状态";
	}

	/**
	 *获取需求审核操作类型名称
	 * @param  [type] $operationType 需求审核操作类型
	 * @return [type]                [description]
	 */
	public static function getCheckOperationName(int $operationType) {
		$operationName = [
			self::PRIMARY_TEAM_LEADER_AGREE_OPERATION => '小组长审核通过',
			self::ADVANCED_TEAM_LEADER_AGREE_OPERATION => '大组长审核通过',
			self::TEAM_MANAGER_AGREE_OPERATION => '主管审核通过',
			self::MANAGER_AGREE_OPERATION => '经理审核通过',
			self::PRIMARY_TEAM_LEADER_REJECT_OPERATION => '小组长驳回',
			self::ADVANCED_TEAM_LEADER_REJECT_OPERATION => '大组长驳回',
			self::TEAM_MANAGER_REJECT_OPERATION => '主管驳回',
			self::MANAGER_REJECT_OPERATION => '经理驳回',
		];

		return $operationName[$operationType] ?? "";
	}

	public function transferToPms() {

	}

	public function addToTransferQueue(int $storyId) {
		/*$story = $this->writeDb->fetchRow("select * from b_story where id=$storyId");
			if (!$story) {
				return $this->_error('id为:' . $storyId . '的需求不存在！');
			}

			if ($story['examine_status'] != self::EXAMINE_PASS) {
				return $this->_error('需求不是待审核通过状态，不能传输pms！');
			}

			$productPurchaseInfo = $this->db->fetchRow("select purchaser,supplier_sn,purchase_price from p_product_purchase where goods_sn=" . $this->db->quote($goodsSn));
			if (!$productPurchaseInfo) {
				return $this->_error('未找到商品所属的采购信息！');
			}
			$queueData = [

		*/

	}

	/**
	 *人工添加特采需求
	 * @param [type] $goodsSn           sku
	 * @param [type] $warehouse         产品所属仓库
	 * @param int    $storyQuantity     特采需求数量
	 * @param string $platformWarehouse 产品所属平台仓
	 */
	public function addSpecialStory($goodsSn, $warehouse, int $storyQuantity, $platformWarehouse = "") {
		//如果特采需求属于某个平台仓，仓库审核规则取平台仓对应的审核规则
		$useWarehouse = ($platformWarehouse == "") ? $warehouse : $platformWarehouse;

		$warehouseInfo = $this->db->fetchRow('select * from c_warehouse where warehouse_code=' . $this->db->quote($useWarehouse));
		if (!$warehouseInfo) {
			return $this->_error("未找到特采需求的所属仓库！");
		}
		$this->writeDb->beginTransaction();
		$today = date("Y-m-d");
		try {
			//如果需求所属的仓库设置为特采需要审核，且需求满足审核的条件，生成一条待小组长审核需求
			if ($warehouseInfo['special_demand_examine'] == 2) {
				try {
					if ($this->_addSpecialStoryNeedCheck($goodsSn, $warehouse, $platformWarehouse, $storyQuantity)) {
						$createResult = $this->_create($goodsSn, $warehouse, self::B_STORY_TYPE, $storyQuantity, $platformWarehouse, $today, self::WAIT_PRIMARY_TEAM_LEADER_EXAMINE);
						if (!$createResult) {
							$this->writeDb->rollBack();
							return $this->_error('生成特采需求失败！');
						}
						$this->writeDb->commit();
						return true;
					}
				} catch (Exception $e) {
					return $this->_error($e->getMessage());
				}
			}
			/**
			 * 其他情况(需求所属仓库设置为不需要审核,或需求不满足小组长审核条件)
			 * 直接生成一条审核通过的需求记录，并将采购需求传输pms
			 *
			 */
			$createResult = $this->_create($goodsSn, $warehouse, self::B_STORY_TYPE, $storyQuantity, $platformWarehouse, $today, self::EXAMINE_PASS);
			if (!$createResult) {
				$this->writeDb->rollBack();
				return $this->_error('生成特采需求失败！');
			}
			$createStoryInfo = $this->getOneByExamineStatus($goodsSn, $warehouse, self::EXAMINE_PASS, $platformWarehouse, $today);
			$addTransferQueue = $this->addToTransferQueue($createStoryInfo['id']);
			if ($addTransferQueue === false) {
				$this->writeDb->rollBack();
				return false;
			}

			//记录审核日志
			$examineLog['handle_user'] = 'system';
			$examineLog['story_id'] = $createStoryInfo['id'];
			$examineLog['handle_role'] = "系统";
			$examineLog['handle_type'] = 1;
			$this->writeDb->insert('b_story_examine_log', $examineLog);

			$this->writeDb->commit();
			return true;

		} catch (Exception $e) {
			$this->writeDb->rollBack();
			return $this->_error($e->getMessage());
		}
	}

	/**
	 * 特采需求是否需要审核
	 * @param [type] $goodsSn           sku
	 * @param [type] $warehouse         产品所属仓库
	 * @param int    $storyQuantity     特采需求数量
	 * @param string $platformWarehouse 产品所属平台仓
	 */
	protected function _addSpecialStoryNeedCheck($goodsSn, $warehouse, $platformWarehouse, int $storyQuantity) {
		//如果特采需求属于某个平台仓，仓库审核规则取平台仓对应的审核规则
		$useWarehouse = ($platformWarehouse == "") ? $warehouse : $platformWarehouse;

		$warehouseInfo = $this->db->fetchRow('select * from c_warehouse where warehouse_code=' . $this->db->quote($useWarehouse));
		if (!$warehouseInfo) {
			throw new Exception("未找到特采需求的所属仓库！");
		}
		//如果仓库设置为不需要审核需求，那么直接审核通过
		if ($warehouseInfo['demand_examine'] == 1) {
			return false;
		}

		//检查需求是否满足小组长审核标准
		//当仓库设置需求需要审核但有没有设置任何详细的审核规则时，默认需要审核
		$warehouseAllCheckRule = $this->db->fetchAll("select * from c_warehouse_ex where warehouse_code=" . $this->db->quote($useWarehouse));
		if (!$warehouseAllCheckRule) {
			return true;
		}
		$warehouseCheckRule = $this->db->fetchRow("select * from c_warehouse_ex where warehouse_code=" . $this->db->quote($useWarehouse) . ' AND auditor=1');
		if (!$warehouseCheckRule) {
			throw new Exception("未找到仓库的需求审核规则！");
		}
		$productPrice = $this->db->fetchOne("select purchase_price from p_product_purchase where goods_sn=" . $this->db->quote($goodsSn));
		if ($productPrice === false) {
			throw new Exception("未找到特采需求所属商品的价格！");
		}
		if (($productPrice * $storyQuantity > $warehouseCheckRule['quota']) || ($storyQuantity > $warehouseCheckRule['maxnum'])) {
			return true;
		}
		return false;
	}

	/**
	 * 获取需求的数量修改日志
	 * @param  int    $storyId 需求id
	 * @return [type]          [description]
	 */
	public function getStoryQuantityModifyLog(int $storyId) {
		return $storyLog = $this->db->fetchAll("select * from b_story_quantity_modify_log where story_id=" . $storyId . ' order by modify_time desc');
	}
}